import org.junit.Assert;
import org.junit.Test;

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
import java.util.stream.Collectors;

@FunctionalInterface
interface MyFunc<T, U, L, O, R> {
    R apply(T t, U u, L l, O o);
}

public class APITest {
    public static <T> T getInstance(String className) throws Exception {
        Class<?> cls = Class.forName(className);
        Constructor<?> constructor = cls.getDeclaredConstructor();
        constructor.setAccessible(true);
        return (T) constructor.newInstance();
    }

    @Test
    public void test2() {
        Class<String> cls = String.class;
//        Method[] methods = cls.getDeclaredMethods();
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }

    @Test
    public void test3() {
        Properties properties = new Properties();
        try (FileReader fileReader = new FileReader("info.prop")) {
            properties.load(fileReader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        properties.list(System.out);
        Enumeration<Object> elements = properties.elements();
        while (elements.hasMoreElements()) {
            System.out.print(elements.nextElement() + " ");
        }
        System.out.println();
    }

    @Test
    public void test1() throws NoSuchFieldException {
        Class<String> stringCls = String.class;
        Field value = stringCls.getDeclaredField("value");
        value.setAccessible(true);
        System.out.println(Modifier.toString(value.getModifiers()));
        System.out.println(value.getType());
    }

    @Test
    public void test4() {
        System.out.println(MessageFormat.format("hello {0}", "bob"));
    }

    @Test
    public void test5() {
        Class<String> cls = String.class;
        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods) {
            StringJoiner sj = new StringJoiner(", ", "(", ")");
            Class<?>[] parameterTypes = m.getParameterTypes();
            for (Class<?> clz : parameterTypes) {
                sj.add(clz.toString());
            }

            System.out.println(Modifier.toString(m.getModifiers()) + " " + m.getName() + sj);
//            System.out.println(m);
        }
    }

    public void method(int i) {
        System.out.println("method(int i)");
        System.out.println(int.class);
    }

    public void method(Integer i) {
        System.out.println("method(Integer i)");
        System.out.println(Integer.class);
    }

    @Test
    public void test6() {
        int i = 1;
        Integer integer = 1;
        method(i);
        method(integer);
    }

    @Test
    public void test7() throws Exception {
        String instance = getInstance("java.lang.String");
        System.out.println(instance.getClass().getName());
    }

    @Test
    public void test8() {
//        DoubleToLongFunction function = (d) -> (long)(d * 100);
//        System.out.println(function.applyAsLong(70.25));

        DoubleToLongFunction func = Math::round;
        System.out.println(func.applyAsLong(-123.5));
    }

    @Test
    public void test9() {
        ToIntBiFunction<Integer, Integer> com1 = Integer::compareTo;
        ToIntBiFunction<Integer, Integer> com2 = Integer::compare;

        System.out.println(com1.applyAsInt(1, 3));
        System.out.println(com2.applyAsInt(3, 1));
    }

    @Test
    public void test10() {
        Supplier<String> stringSupplier = String::new;
        String s = stringSupplier.get();
        System.out.println(s.getClass().getName());
    }

    @Test
    public void test11() {
        Function<String, String> func = String::new;
        System.out.println(func.apply("HelloLambda"));
    }

    @Test
    public void test12() {
        Function<Integer, LambdaTest> integerFunc = LambdaTest::new;
        Function<Integer, LambdaTest> intFunc = (i) -> new LambdaTest(i.intValue());
        integerFunc.apply(0); // LambdaTest(Integer i)
        intFunc.apply(1); // LambdaTest(int i)

        MyFunc<Integer, Double, Boolean, String, LambdaTest> func = LambdaTest::new;
        LambdaTest lambda = func.apply(1, 2.0, true, "你好");
    }

    @Test
    public void test13() {
        IntFunction<int[]> intArrayGenerator = int[]::new; // 因为构造数组需要指定长度，所以会有一个参数
        int[] ints = intArrayGenerator.apply(100);
        System.out.println(ints.length);
    }

    @Test
    public void test14() {
        int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(arr)); // 错误的，基本类型数组不能这么玩
        Integer[] arr2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(arr2)); // ok
        for (int i : arrayList) {
            System.out.print(i + " ");
        }
        System.out.println();
    }

    @Test
    public void test15() {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        ArrayList<Integer> arrayList = Arrays.stream(arr).boxed().collect(Collectors.toCollection(ArrayList::new));
        arrayList.forEach(System.out::print);
    }

    @Test
    public void test16() {
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
        AtomicInteger sum = new AtomicInteger();
//        arrayList.parallelStream().forEach(sum::addAndGet);
//        System.out.println(sum);
//        arrayList.parallelStream().reduce(Integer::sum).ifPresent(System.out::println);
//        System.out.println(arrayList.parallelStream().reduce(100, Integer::sum));
        System.out.println(arrayList.parallelStream().reduce(Integer::sum).orElseThrow(RuntimeException::new));

    }

    @Test
    public void test17() {
        String[] str = {"aa", "bb", "cc", "dd"};
//        Arrays.stream(str).forEach((string) -> System.out.println(string.toUpperCase()));
//        str = Arrays.stream(str).map(String::toUpperCase).toArray(String[]::new);
//        System.out.println(Arrays.toString(str));
        Arrays.stream(str).map(String::toUpperCase).forEach((string) -> System.out.print(string + " "));
    }

    @Test
    public void test18() {
        Random random = new Random(System.currentTimeMillis());
        int[] array = new int[100000000];
        for (int i = 0; i < array.length; i++) {
            array[i] = random.nextInt(1001);
        }

        long start = System.currentTimeMillis();
        long sum1 = Arrays.stream(array).reduce(0, Integer::sum);
        long end = System.currentTimeMillis();
        System.out.println("串行执行一共花费了" + (end - start) + "ms");

        start = System.currentTimeMillis();
        long sum2 = Arrays.stream(array).parallel().reduce(0, Integer::sum);
        end = System.currentTimeMillis();
        System.out.println("并行执行一共花费了" + (end - start) + "ms");

        Assert.assertEquals(sum1, sum2);
        System.out.println("sum1 = " + sum1);
    }

    @Test
    public void test19() {
        String s = """
                https://baidu.com
                https://kotoriforest.us.kg
                """;
        System.out.println(s);
    }

    @Test
    public void test20() {
        int i = 10;
        switchPattern((byte) 127);
    }

    public void switchPattern(Object o) {
        switch (o) {
            case Integer i -> System.out.println("Integer i = " + i);
            case Double d -> System.out.println("Double d = " + d);
            case Boolean b -> System.out.println("Boolean b = " + b);
            case String s -> System.out.println("String s = " + s);
            default -> System.out.println("Default Value = " + o);
        }
    }

    @Test
    public void test21() {
////        Optional<String> optional = Optional.of("空指针");
//        Optional<String> optional = Optional.empty();
//        System.out.print("""
//                first line
//                \u0009
//                third line
//                """.translateEscapes());
    }

    @Test
    public void test22() {
        System.out.println("             ".isBlank());
    }
}

class LambdaTest {
    public LambdaTest() {
        System.out.println("LambdaTest()");
    }

    public LambdaTest(int i) {
        System.out.println("LambdaTest(int i)");
    }

    public LambdaTest(Integer i) {
        System.out.println("LambdaTest(Integer i)");
    }

    public LambdaTest(int i, double d, boolean b, String s) {
        System.out.println("LambdaTest(int i, int d, boolean b, String s)");
    }
}